package org.apache.tomcat.util.file;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.net.MalformedURLException;
import java.net.URI;
import java.net.URL;
import java.nio.file.Files;
import org.apache.tomcat.util.buf.UriUtil;

/**
 * 配置文件源
 *
 * @author chentudong
 * @date 2024/2/19 14:58
 * @since 1.0
 */
public interface ConfigurationSource {

  ConfigurationSource DEFAULT = new ConfigurationSource() {
    final File userDir = new File(System.getProperty("user.dir"));
    final URI userDirUri = userDir.toURI();

    @Override
    public Resource getResource(String name) throws IOException {
      if (!UriUtil.isAbsoluteURI(name)) {
        File file = new File(name);
        if(!file.isAbsolute()){
          file = new File(userDir, name);
        }
        if(file.isFile()){
          return new Resource(Files.newInputStream(file.toPath()), file.toURI());
        }
      }

      URI uri;
      try {
        uri = userDirUri.resolve(name);
      } catch (IllegalArgumentException e) {
        throw new FileNotFoundException(name);
      }

      try {
        URL url = uri.toURL();
        return new Resource(url.openConnection().getInputStream(), uri);
      } catch (MalformedURLException e) {
        throw new FileNotFoundException(name);
      }
    }
  };

  default Resource getConfResource(String name) throws IOException {
    return getResource("conf/" + name);
  }

  default Resource getServerXml()
      throws IOException {
    return getConfResource("server.xml");
  }

  Resource getResource(String name) throws IOException;

  class Resource implements AutoCloseable {

    private final InputStream inputStream;

    private final URI uri;

    public Resource(InputStream inputStream, URI uri) {
      this.inputStream = inputStream;
      this.uri = uri;
    }

    public InputStream getInputStream() {
      return inputStream;
    }

    public URI getURI() {
      return uri;
    }

    @Override
    public void close() throws Exception {
      if (inputStream != null) {
        inputStream.close();
      }
    }
  }
}
